package com.papper.mng.aspect;

import com.papper.common.annotation.PapperLog;
import com.papper.common.bean.sys.SysUser;
import com.papper.common.constant.SystemConstants;
import com.papper.common.factory.PapperLogTool;
import com.papper.common.utils.tool.StringTool;
import com.papper.mng.controller.WebContext;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * WebLogAspect
 * <h5>描述: 日志统一处理</h5>
 */
@Aspect
@Component
public class PapperLogAspect {
	private static final Logger logger = LoggerFactory.getLogger("PapperLog");

	@Pointcut("@annotation(com.papper.common.annotation.PapperLog)")
	public void operationLog() {
	}

	/**
	 * 环绕增强，相当于MethodInterceptor
	 */
	@Around("operationLog()")
	public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
		Object res  = null;
		long   time = System.currentTimeMillis();
		try {
			res = joinPoint.proceed();
			time = System.currentTimeMillis() - time;
			return res;
		} finally {
			try {
				addOperationLog(joinPoint, res, time);
			} catch (Exception e) {
				logger.error("LogAspect 操作失败：" + e.getMessage());
				e.printStackTrace();
			}
		}
	}

	private void addOperationLog(JoinPoint joinPoint, Object res, long time) {
		MethodSignature                        signature  = (MethodSignature) joinPoint.getSignature();
		com.papper.common.annotation.PapperLog annotation = signature.getMethod().getAnnotation(com.papper.common.annotation.PapperLog.class);
		if (annotation != null) {
			SysUser sysUser = (SysUser) WebContext.getServletRequest().getSession().getAttribute(SystemConstants.SESSION.SESSION_ADMIN_LOGIN);
			String  linkId  = sysUser == null ? "游客" : sysUser.getLoginName();
			String  content = getDetail(((MethodSignature) joinPoint.getSignature()).getParameterNames(), joinPoint.getArgs(), annotation);
			PapperLogTool.OPER(signature.getDeclaringTypeName(), linkId, signature.getName(), content);
		}
	}

	/**
	 * 对当前登录用户和占位符处理
	 *
	 * @param argNames   方法参数名称数组
	 * @param args       方法参数数组
	 * @param annotation 注解信息
	 * @return 返回处理后的描述
	 */
	private String getDetail(String[] argNames, Object[] args, PapperLog annotation) {
		Map<Object, Object> map = new HashMap<>(4);
		for (int i = 0; i < argNames.length; i++) {
			map.put(argNames[i], args[i]);
		}
		String detail = annotation.detail();
		try {
			for (Map.Entry<Object, Object> entry : map.entrySet()) {
				Object k = entry.getKey();
				Object v = entry.getValue();
				detail = detail.replace("{{" + k + "}}", StringTool.nullToEmpty(v));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return detail;
	}

	@Before("operationLog()")
	public void doBeforeAdvice(JoinPoint joinPoint) {
	}

	@AfterReturning(returning = "ret", pointcut = "operationLog()")
	public void doAfterReturning(Object ret) throws Throwable {
	}

	/**
	 * 后置异常通知
	 */
	@AfterThrowing("operationLog()")
	public void throwss(JoinPoint jp) {
		logger.error("日志注解拦截异常:{}", jp.toString());
	}

	/**
	 * 后置最终通知,final增强，不管是抛出异常或者正常退出都会执行
	 */
	@After("operationLog()")
	public void after(JoinPoint jp) {
	}
}
